/*

async 和其他并发模型比较
OS 线程， 它最简单，也无需改变任何编程模型(业务/代码逻辑)，因此非常适合作为语言的原生并发模型，
我们在多线程章节也提到过，Rust 就选择了原生支持线程级的并发编程。但是，这种模型也有缺点，
例如线程间的同步将变得更加困难，线程间的上下文切换损耗较大。使用线程池在一定程度上可以提升性能，但是对于 IO 密集的场景来说，线程池还是不够。

事件驱动(Event driven)， 这个名词你可能比较陌生，如果说事件驱动常常跟回调( Callback )一起使用，
相信大家就恍然大悟了。这种模型性能相当的好，但最大的问题就是存在回调地狱的风险：
非线性的控制流和结果处理导致了数据流向和错误传播变得难以掌控，还会导致代码可维护性和可读性的大幅降低，大名鼎鼎的 JavaScript 曾经就存在回调地狱。

协程(Coroutines) 可能是目前最火的并发模型，Go 语言的协程设计就非常优秀，这也是 Go 语言能够迅速火遍全球的杀手锏之一。
协程跟线程类似，无需改变编程模型，同时，它也跟 async 类似，可以支持大量的任务并发运行。
但协程抽象层次过高，导致用户无法接触到底层的细节，这对于系统编程语言和自定义异步运行时是难以接受的++

actor 模型是 erlang 的杀手锏之一，它将所有并发计算分割成一个一个单元，这些单元被称为 actor ，
单元之间通过消息传递的方式进行通信和数据传递，跟分布式系统的设计理念非常相像。
由于 actor 模型跟现实很贴近，因此它相对来说更容易实现，但是一旦遇到流控制、失败重试等场景时，就会变得不太好用


async/await， 该模型性能高，还能支持底层编程，同时又像线程和协程那样无需过多的改变编程模型，
但有得必有失，async 模型的问题就是内部实现机制过于复杂，对于用户来说，理解和使用起来也没有线程和协程简单，
好在前者的复杂性开发者们已经帮我们封装好，而理解和使用起来不够简单，正是本章试图解决的问题。
*/

// `block_on`会阻塞当前线程直到指定的`Future`执行完成，这种阻塞当前线程以等待任务完成的方式较为简单、粗暴，
// 好在其它运行时的执行器(executor)会提供更加复杂的行为，例如将多个`future`调度到同一个线程上执行。

use futures::executor::block_on;

pub async fn run1() {
    
    println!("大王叫我来巡山");
}


pub async fn run2() {

    println!("二王叫我来巡海")
}
pub async fn run3(){
    println!("三王叫我来巡山"); 
}

pub async  fn run4(){
    println!("四王叫我来巡山"); 
}


pub async fn run() {
    //let r = run1();
    //let r2=run2();
    //block_on(r); //需要用一个执行器包裹 这个异步函数，block_on 阻塞当前线程等待任务完成
    //block_on(r2);
    //run2().await;
    //run1().await;

   
     
     // 方法2：使用 await（需要在 async 函数中）
     run1().await;
     run2().await;
   
}
